home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 07 - 1991 / 07.10 Oct 91 / Diamond WDEF Source / DiamondDef.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-27  |  24.0 KB  |  868 lines  |  [TEXT/Dpnt]

  1. /* ==========================================================================
  2.  
  3. File: DiamondDef.c
  4. Function: Defines the Diamond Window.
  5. History: 7/4/90  &  8/26/90 - 12/1/90  &  2/15/91 - 4/22/91 : Marz. 
  6.  
  7. ============================================================================= */
  8.  
  9. #include "DiamondDef.h"
  10. #include <SetUpA4.h>
  11.  
  12.  
  13. #define            wJUST_DRAGGED            50
  14. #define            wNEW_TITLE                51
  15. #define            DRAW_WINDOW_FRAME        0
  16.  
  17. #define            ZOOM_MASK                8
  18. #define            NO_GROW_MASK            4
  19.  
  20. #define            SCREEN_MARGIN            3
  21. #define            FRAME_WIDTH                25
  22. #define            SHADOW                    3
  23. #define            LEFT_SIDE                TRUE
  24. #define            FULL_RESERVE            51
  25. #define            TOP_RESERVE                30
  26. #define            BOTTOM_RESERVE            13
  27.  
  28. #define            FIRST_CHAR                1
  29.  
  30.  
  31. static Pattern    white = {0}, black = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0xFF, 0xFF,
  32.                 0xFF}, gray = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};
  33.  
  34. DataRecord        dataRecord;
  35. DataRecordHdl    dataRecordHdl;
  36.  
  37. /* =========================================================================== */
  38.  
  39. void   CalcRgns(WindowPeek   theWindow)
  40. {
  41. /* Calculates the structure, content, and title regions of diamond windows when
  42. they are created or after they have been dragged or resized.
  43. */
  44. GrafPtr            savedPort;
  45. Rect            theRect, strucRect, polyRect;
  46. short            halfPort, halfStruc, xOffset, yOffset;
  47.  
  48.     theRect = theWindow->port.portRect;
  49. /* The contentRgn extends beyond the portRect.  This means origin is
  50. automatically offset so that it begins just outside the scroll bar area,
  51. regardless of whether or not the window actually has a grow region.
  52. */
  53.     halfPort = halfStruc = (theRect.right - theRect.left) >> 1;
  54.     halfStruc += 26;
  55. /* This routine needs the portRect in Global coordinates for drawing in the WMgr port.
  56. By switching the current port to the window's port and pretending a rectangle is two
  57. points this can be achieved.
  58. */ 
  59.     GetPort(&savedPort);
  60.     SetPort(theWindow);
  61.     LocalToGlobal(&topLeft(theRect));
  62.     LocalToGlobal(&botRight(theRect));
  63.     SetPort(savedPort);    
  64.     if (EqualRect(&theRect, &dataRecord.stdRect))
  65.     {
  66.     /* window was resized by being zoomed, don't change dataRecord.myRect, it
  67.     holds the previous size of the portRect for use with inZoomIn.
  68.     */
  69.         strucRect = theRect;
  70.         dataRecord.zoomedOut = TRUE;
  71.     }
  72.     else
  73.     {
  74.     /* window has been resized w/o being zoomed, save the new window size for
  75.     later inZoom-ing.
  76.     */
  77.         dataRecord.myRect = strucRect = theRect;
  78.          dataRecord.zoomedOut = FALSE;
  79.      }
  80. /* Get the strucRect.  dataRecord.midX and dataRecord.midY are the Global
  81. coordinates of the middle of the window.
  82. */
  83.     InsetRect(&strucRect, -26, -26);
  84.     dataRecord.midX = (strucRect.left + strucRect.right) >> 1;
  85.     dataRecord.midY = (strucRect.top + strucRect.bottom) >> 1;
  86. /* Get the strucRgn                                                                    */
  87.     OpenRgn();
  88.         MoveTo(strucRect.left, dataRecord.midY);
  89.         Line(halfStruc, -halfStruc);
  90.         Line(2, 0);
  91.         Line(halfStruc, halfStruc);
  92.         Line(0, 1);
  93.         Line(-halfStruc, halfStruc);
  94.         Line(-2, 0);
  95.         Line(-halfStruc, -halfStruc);
  96.         Line(0, -1);
  97.     CloseRgn(theWindow->strucRgn);
  98.  
  99. /* Define the titleRgn.  There are a couple of notes of interest here.
  100.         1)     ErasePoly() actually calls NewRgn() and makes a region out of the
  101.             polygon in order to know what to erase.
  102.         2)    I only used titlePoly to erase the title area anyway so why not just
  103.             make it a region and save time?
  104. */
  105.     OpenRgn();
  106.         MoveTo(theRect.left - 26, dataRecord.midY);
  107.         Line(26, 0);
  108.         Line(halfPort, halfPort);
  109.         Line(halfPort, -halfPort);
  110.         Line(26, 0);
  111.         Line(-halfStruc, halfStruc);
  112.         Line(-halfStruc, -halfStruc);
  113.     CloseRgn(dataRecord.titleRgn);
  114. /* Define the content region.                                                */
  115.     halfStruc --;
  116.     OpenRgn();
  117.         MoveTo(dataRecord.midX, theRect.top - 25);
  118.         Line(halfStruc, halfStruc);
  119.         Line(-25, 0);
  120.         Line(-halfPort, halfPort);
  121.         Line(-halfPort, -halfPort);
  122.         Line(-25, 0);
  123.         Line(halfStruc, -halfStruc);
  124.     CloseRgn(theWindow->contRgn);
  125. /* The following lines offset various window parts to the updated locations.  The
  126. window parts are only updated if they are present.
  127. */
  128.     if (theWindow->goAwayFlag)
  129.     {
  130.         HLock(dataRecord.goAwayPoly);
  131.         polyRect = (**(dataRecord.goAwayPoly)).polyBBox;
  132.         HUnlock(dataRecord.goAwayPoly);
  133.         xOffset = -polyRect.left + strucRect.left + 18;
  134.         yOffset = -polyRect.top + dataRecord.midY + 5;
  135.         OffsetPoly(dataRecord.goAwayPoly, xOffset, yOffset);
  136.         OffsetRgn(dataRecord.goAwayRgn, xOffset, yOffset);
  137.     }
  138.     if (theWindow->spareFlag)
  139.     {
  140.         HLock(dataRecord.zoomPoly);
  141.         polyRect = (**(dataRecord.zoomPoly)).polyBBox;
  142.         HUnlock(dataRecord.zoomPoly);
  143.         xOffset = -polyRect.left + strucRect.right - 34;
  144.         yOffset = -polyRect.top + dataRecord.midY + 5;
  145.         OffsetPoly(dataRecord.zoomPoly, xOffset, yOffset);
  146.         OffsetRgn(dataRecord.zoomRgn, xOffset, yOffset);
  147.     }
  148.     if (dataRecord.resizable)
  149.     {
  150.         HLock(dataRecord.growPoly);
  151.         polyRect = (**(dataRecord.growPoly)).polyBBox;
  152.         HUnlock(dataRecord.growPoly);
  153.         xOffset = -polyRect.left + dataRecord.midX - 8;
  154.         yOffset = -polyRect.top + strucRect.bottom - 24;
  155.         OffsetPoly(dataRecord.growPoly, xOffset, yOffset);
  156.         OffsetRgn(dataRecord.growRgn, xOffset,    yOffset);
  157. /* Make the clipRgn which will prevent drawing from occuring within the slider
  158. area.  This region will later have to be suspended to allow for the drawing of
  159. the sliders themselves.
  160. When working with clipRgns it is important to remember how the Mac coordinate system works.  Recall that the pen hangs down and to the right one pixel of the actual location of the pen.  The following few lines compensate for this.
  161. */
  162.         SetPort(theWindow);
  163.         OpenRgn();
  164.             theRect = theWindow->port.portRect;
  165.             MoveTo(theRect.left, theRect.top + halfPort);
  166.             Line (1, 0);
  167.             Line(halfPort - 1, -halfPort + 1);
  168.             Line(halfPort - 1, halfPort - 1);
  169.             Line (1, 0);
  170.             Line(-halfPort, halfPort);
  171.             Line(-halfPort, -halfPort);
  172.         CloseRgn(theWindow->port.clipRgn);
  173.         SetPort(savedPort);
  174.     }
  175. /* Find how much space is available in each window half for writing the title in.
  176. */
  177.     dataRecord.halfTitleSpace = halfStruc - FULL_RESERVE;
  178. }
  179.  
  180.  
  181.  
  182. void    ToggleGoAwayBox()
  183. {
  184. /*    Indicates when the close region of a diamond window is selected by drawing an
  185. asterisk-like symbol within the region.  First the image is drawn into an
  186. offscreen BitMap using StuffHex(), then the image is tranferred to the WMgrPort
  187. by means of the CopyBits() procedure.
  188. */
  189. BitMap        closeBitMap;
  190. GrafPtr        windMngrPort;
  191. Rect        tempRect, myRect;
  192.  
  193.     closeBitMap.baseAddr = NewPtr(0x34);
  194.     StuffHex(closeBitMap.baseAddr, "002000200020012400A80000");
  195.     StuffHex(closeBitMap.baseAddr + 12, "0F8F800000A801240020002000200");
  196.     closeBitMap.rowBytes = 2;
  197.     closeBitMap.bounds.top = closeBitMap.bounds.left = 0;
  198.     closeBitMap.bounds.bottom = closeBitMap.bounds.right = 13;
  199.     myRect = closeBitMap.bounds;
  200.     tempRect = (**dataRecord.goAwayPoly).polyBBox;
  201.     OffsetRect(&myRect, tempRect.left + 2, tempRect.top + 2);
  202.     GetWMgrPort(&windMngrPort);
  203.     CopyBits(&closeBitMap, &windMngrPort->portBits, &closeBitMap.bounds,
  204.         &myRect, srcXor, NULL);
  205.     DisposPtr(closeBitMap.baseAddr);
  206. }
  207.  
  208.  
  209.  
  210. void    ToggleZoomBox()
  211. {
  212. /* As ToggleGoAwayBox().
  213. */
  214. BitMap        zoomBitMap;
  215. GrafPtr        windMngrPort;
  216. Rect        tempRect, myRect;
  217.  
  218.     zoomBitMap.baseAddr = NewPtr(0x34);
  219.     StuffHex(zoomBitMap.baseAddr, "0020002000A0016400A80010");
  220.     StuffHex(zoomBitMap.baseAddr + 12, "0F8F801000A8016400A0002000200");
  221.     zoomBitMap.rowBytes = 2;
  222.     zoomBitMap.bounds.top = zoomBitMap.bounds.left = 0;
  223.     zoomBitMap.bounds.bottom = zoomBitMap.bounds.right = 13;
  224.     myRect = zoomBitMap.bounds;
  225.     tempRect = (**dataRecord.zoomPoly).polyBBox;
  226.     OffsetRect(&myRect, tempRect.left + 2, tempRect.top + 2);
  227.     GetWMgrPort(&windMngrPort);
  228.     CopyBits(&zoomBitMap, &windMngrPort->portBits, &zoomBitMap.bounds,
  229.         &myRect, srcXor, NULL);
  230.     DisposPtr(zoomBitMap.baseAddr);
  231. }
  232.  
  233.  
  234.  
  235. void    EraseTitleSpace(Boolean   leftSide, short   length)
  236. {
  237. /* Clears space for the window's title to be drawn in.
  238. */
  239. RgnHandle        theRgn;
  240.  
  241.     theRgn = NewRgn();
  242.     OpenRgn();
  243.     if (leftSide)
  244.     {
  245.         Line(length, length);
  246.         Line(11, -11);
  247.         Line(-length, -length);
  248.         Line(-11, 11);
  249.     }
  250.     else
  251.     {
  252.         Line(length, -length);
  253.         Line(-11, -11);
  254.         Line(-length, length);
  255.         Line(11, 11);
  256.     }
  257.     CloseRgn(theRgn);
  258.     EraseRgn(theRgn);
  259.     DisposeRgn(theRgn);
  260. }
  261.  
  262.  
  263.  
  264. void    DrawChars(short   startSpot, short   stopSpot, Ptr   theTitle)
  265. {
  266. /*    Draws the characters of the window's title on a diagonal slant.  If
  267. (start == FIRST_CHAR) then text is drawn on a downward slant, otherwise text is
  268. drawn on an upward slant beginning with the character specified by startSpot.
  269. */
  270. char        ch;
  271. short        yOffset, index, charWidth, xAdjust;
  272.  
  273.     if (startSpot == FIRST_CHAR)
  274.         yOffset = 8;
  275.     else
  276.         yOffset = -8;
  277.     index = startSpot;
  278.     while (index <= stopSpot)
  279.     {
  280.         ch = *(theTitle + index);
  281.         charWidth = CharWidth(ch);        
  282.         xAdjust = charWidth >> 1;
  283.         Move(-xAdjust, 0);
  284.         DrawChar(ch);
  285.         Move(-(charWidth - xAdjust) + 8, yOffset);
  286.         index ++;
  287.     }
  288. }    
  289.     
  290.  
  291.  
  292. void    DrawTitle(WindowPeek   theWindow, Rect   strucRect)
  293. {
  294. /*    Decides how text should appear, depending on the size of the window and its
  295. title. Positions the pen and oversees text drawing.
  296. */
  297. Ptr                theTitle;
  298. short            totalWidth, oneSide, adjust, penOffset, mostChars, leftChars;
  299. StringHandle    titleHandle;
  300.  
  301.     titleHandle = theWindow->titleHandle;
  302.     HLock(titleHandle);
  303.     theTitle = (Ptr) *titleHandle;
  304.     totalWidth = (dataRecord.numChars << 3) + 10;
  305.     oneSide = (strucRect.right - strucRect.left) >> 1;
  306.     if (totalWidth <= dataRecord.halfTitleSpace)
  307.     {
  308.         adjust = ((oneSide - totalWidth) >> 1) + 7;
  309.         MoveTo(strucRect.left + adjust, dataRecord.midY + adjust);
  310.         EraseTitleSpace(LEFT_SIDE, totalWidth);
  311.         Move(16, 7);
  312.         DrawChars(FIRST_CHAR, dataRecord.numChars, theTitle);
  313.     }
  314.     else
  315.     {
  316.         mostChars = dataRecord.numChars - dataRecord.leftStop;
  317.         if (mostChars < dataRecord.leftStop)
  318.             mostChars = dataRecord.leftStop;
  319.         if ((mostChars << 3) < (dataRecord.halfTitleSpace))
  320.         {
  321.         /* word break on space                        */
  322.             penOffset = (dataRecord.leftStop << 3) + 5;
  323.             MoveTo(dataRecord.midX - BOTTOM_RESERVE - 3, strucRect.bottom - BOTTOM_RESERVE - 3);
  324.             Move(-penOffset, -penOffset);
  325.             EraseTitleSpace(LEFT_SIDE, penOffset);
  326.             Move(14, 5);
  327.             DrawChars(FIRST_CHAR, dataRecord.leftStop, theTitle);
  328.         /* don't forget to remove the excess space    */
  329.             penOffset = (dataRecord.numChars - dataRecord.leftStop - 1) << 3;
  330.             MoveTo(dataRecord.midX + BOTTOM_RESERVE + 3, strucRect.bottom - BOTTOM_RESERVE - 3);
  331.             EraseTitleSpace(!LEFT_SIDE, penOffset + 5);
  332.             Move(1, -8);
  333.             DrawChars(dataRecord.leftStop + 2, dataRecord.numChars, theTitle);
  334.         }
  335.         else
  336.         {
  337.         /* no word break on space                    */
  338.             leftChars = dataRecord.halfTitleSpace >> 3;
  339.             penOffset = dataRecord.halfTitleSpace + 4;
  340.             MoveTo(dataRecord.midX - BOTTOM_RESERVE - 3, strucRect.bottom - BOTTOM_RESERVE - 3);
  341.             Move(-penOffset, -penOffset);
  342.             EraseTitleSpace(LEFT_SIDE, penOffset);
  343.             Move(14, 5);
  344.             DrawChars(FIRST_CHAR, leftChars, theTitle);
  345.             MoveTo(dataRecord.midX + BOTTOM_RESERVE + 3, strucRect.bottom - BOTTOM_RESERVE - 3);
  346.             mostChars = leftChars << 1;
  347.             if (mostChars > dataRecord.numChars)
  348.             {
  349.                 mostChars = dataRecord.numChars;
  350.                 penOffset = ((dataRecord.numChars - leftChars) << 3) + 4;
  351.             }
  352.             EraseTitleSpace(!LEFT_SIDE, penOffset);
  353.             Move(0, -7);
  354.             DrawChars(leftChars + 1, mostChars, theTitle);
  355.         }
  356.     }
  357.     HUnlock(titleHandle);
  358. }
  359.  
  360.  
  361.  
  362. void   DrawWindow(WindowPeek   theWindow, long   param)
  363. {
  364. /* Draws diamond window frames and titles as appropriate.
  365. */
  366. Rect            strucRect;
  367. short            halfPort, halfStruc, index;
  368.  
  369.     if (theWindow->visible)
  370.         switch(LoWord(param))
  371.         {
  372.             case wInGoAway:
  373.                 ToggleGoAwayBox();
  374.                 break;
  375.             case wInZoomIn:
  376.             case wInZoomOut:
  377.                 ToggleZoomBox();
  378.                 break;
  379.             default:
  380. /* Draw window frame.                                                    */
  381.                 if (theWindow->titleWidth)
  382.                 {
  383.                     CalcRgns(theWindow);
  384.                     theWindow->titleWidth = FALSE;
  385.                 }
  386.                 if (dataRecord.zoomedOut)
  387.                     strucRect = dataRecord.stdRect;
  388.                 else
  389.                     strucRect = dataRecord.myRect;
  390.                 InsetRect(&strucRect, -26, -26);
  391.                 halfStruc = halfPort = (strucRect.right - strucRect.left) >> 1;
  392.                 halfPort -= 26;
  393.                 MoveTo(strucRect.left, dataRecord.midY);
  394.                 Line(halfStruc, -halfStruc);
  395.                 PenSize(3, 1);
  396.                 Line(halfStruc, halfStruc);
  397.                 Line(-halfStruc, halfStruc);
  398.                 PenSize(1, 1);
  399.                 Line(-halfStruc, -halfStruc);
  400. /*    Draw content stuff                                                    */
  401.                 EraseRgn(dataRecord.titleRgn);
  402. /* Outline the content region {and the title region}.                    */
  403.                 Line(26, 0);
  404.                 Line(halfPort, halfPort);
  405.                 Line(halfPort, -halfPort);
  406.                 Line(25, 0);
  407.                 if (theWindow->hilited)
  408.                 {
  409.                     MoveTo(strucRect.left + 23, dataRecord.midY + 2);        
  410.                     index = halfStruc - 3;
  411.                     for (halfStruc = index - 20; halfStruc < index; halfStruc += 4)
  412.                     {
  413.                         Line(halfStruc, halfStruc);
  414.                         Line(halfStruc, -halfStruc);
  415.                         Move(-(halfStruc << 1) - 4, 0);
  416.                     }
  417.                     if (theWindow->goAwayFlag)
  418.                     {
  419.                         PenPat(&white);
  420.                         PenSize(1, 1);
  421.                         MoveTo(strucRect.left + 17, dataRecord.midY + 12);
  422.                         Line(8, -8);
  423.                         Move(0, 20);
  424.                         Line(10, -10);
  425.                         PenPat(&black);
  426.                         EraseRgn(dataRecord.goAwayRgn);
  427.                         FramePoly(dataRecord.goAwayPoly);
  428.                     }
  429.                     if (theWindow->spareFlag)
  430.                     {
  431.                         PenPat(&white);
  432.                         PenSize(1, 1);
  433.                         MoveTo(strucRect.right - 17, dataRecord.midY + 12);
  434.                         Line(-8, -8);
  435.                         Move(0, 20);
  436.                         Line(-10, -10);
  437.                         PenPat(&black);
  438.                         EraseRgn(dataRecord.zoomRgn);
  439.                         FramePoly(dataRecord.zoomPoly);
  440.                     }
  441.                     if (dataRecord.resizable)
  442.                     {
  443.                         InsetRgn(dataRecord.growRgn, -2, 0);
  444.                         EraseRgn(dataRecord.growRgn);
  445.                         InsetRgn(dataRecord.growRgn, 2, 0);
  446.                         FramePoly(dataRecord.growPoly);
  447.                     }
  448.                 }    /* if window is hilited                                */
  449.                 DrawTitle(theWindow, strucRect);
  450.                 break;
  451.         } /* end switch                                                    */    
  452. }
  453.  
  454.  
  455.  
  456. NewTitle(WindowPeek   theWindow, Ptr   theTitle)
  457. {
  458. /*    Resets the handle size for the window's title, then BlockMove()s the new
  459. information into it.  Next the space closest to the true center of the title is
  460. found and recorded in the variable leftStop {if no space is found the entire
  461. title's length is stored in leftStop}.  This information, coupled with the
  462. window's current size, is used to determine how the the window's title should be
  463. drawn {all on the left side, split at a space and part drawn on each side, etc.}.
  464.     NewTitle() should only be called when the window is given a new title.
  465. */
  466. char                ch;
  467. GrafPtr                savedPort;
  468. Ptr                    middleChar;
  469. RgnHandle            theRgn;
  470. short                leftChars, index;
  471. StringHandle        titleHandle;
  472. WindowPeek            windMgrPort;
  473.  
  474.     dataRecord.numChars = *theTitle;
  475.     titleHandle = theWindow->titleHandle;
  476.     SetHandleSize(titleHandle, dataRecord.numChars + 1);
  477.     BlockMove(theTitle, *titleHandle, dataRecord.numChars + 1);
  478.     HLock(titleHandle);
  479.     leftChars = dataRecord.numChars >> 1;        /* divide in half        */
  480.     middleChar = theTitle + leftChars;
  481.     for (index = 0; index <= leftChars; index ++)
  482.     {
  483.         ch = *(middleChar - index);
  484.         if (ch == 0x20)
  485.         {
  486.             dataRecord.leftStop = leftChars - index - 1;
  487.             break;
  488.         }
  489.         else
  490.         {
  491.             ch = *(middleChar + index);
  492.             if (ch == 0x20)
  493.             {
  494.                 dataRecord.leftStop = leftChars + index - 1;
  495.                 break;
  496.             }
  497.         }
  498.     }
  499.     if (index > leftChars)
  500.         dataRecord.leftStop = dataRecord.numChars;
  501.     HUnlock(titleHandle);
  502.     /* When dataRecord.titleRgn == NULL, the window is new and therefore its
  503.     titleRgn has not yet been properly set up by CalcRgns(). Setting a clipRgn
  504.     to an uninitialized region is a fatal error so SetClip() should NOT be called
  505.     under this circumstance.
  506.     */
  507.     if ((theWindow->visible) && (dataRecord.titleRgn != NULL))
  508.     {
  509.         GetPort(&savedPort);
  510.         GetWMgrPort(&windMgrPort);
  511.         SetPort(windMgrPort);
  512.         theRgn = NewRgn();
  513.         GetClip(theRgn);
  514.     /* The visRgn does not include any of the window's strucRgn, only the visible
  515.     portion of its contRgn. There's no point in dealing with the entire visible
  516.     strucRgn, just the part of it used to display the window's title since that's
  517.     all that's being altered.  So the WDEF just sets the window manager's clipRgn
  518.     to the window's titleRgn and calls ClipAbove() to subtract the strucRgns of
  519.     all visible window's in front of the window whos title has been changed.
  520.     */
  521.         SetClip(dataRecord.titleRgn);
  522.         ClipAbove(theWindow);
  523.         DrawWindow(theWindow, DRAW_WINDOW_FRAME);
  524.         SetClip(theRgn);
  525.     /* SetClip() copies the specified region into the clipRgn member of the
  526.     current port.  It's up to the programmer to release the memory occupied by
  527.     the original region.
  528.     */
  529.         DisposeRgn(theRgn);
  530.         SetPort(savedPort);
  531.     }
  532. }
  533.  
  534.  
  535.  
  536. void    DrawGrowIcon(WindowPeek   theWindow)
  537. {
  538. /*    Draws the part of the grow icon that is in the content region of the window.
  539. It is not feasible to draw the gIcon as part of the window frame because,
  540. although the icon is properly drawn with much less effort, it is often times
  541. incorrectly erased by the Window Manager when the window is resized {the WManager
  542. has to erase the content region to ensure that no desktop slop shows through}. 
  543. */
  544. GrafPtr            savedPort;
  545. PenState        savedPenState;
  546. Rect            portRect;
  547. RgnHandle        clipRgn;
  548. short            halfPort;
  549.  
  550.     if (dataRecord.resizable)
  551.         if (theWindow->visible)
  552.         {
  553.             GetPort(&savedPort);
  554.             SetPort(theWindow);
  555.             GetPenState(&savedPenState);
  556.             PenNormal();
  557.             clipRgn = NewRgn();
  558.             GetClip(clipRgn);
  559.     /* Must take into consideration the coordinates of the origin in case
  560.     SetOrigin() has been called with values other than (0, 0).  Remember, this
  561.     drawing occurs within the window's own grafport.
  562.     */
  563.             portRect = theWindow->port.portRect;
  564.             halfPort = (portRect.right - portRect.left) >> 1;
  565.             MoveTo(portRect.left, portRect.top + halfPort);
  566.             portRect.top -= 26;
  567.             ClipRect(&portRect);
  568.             Line(halfPort, -halfPort);
  569.             Line(0, -25);
  570.             Move(0, 25);
  571.             Line(halfPort, halfPort);
  572.             SetPenState(&savedPenState);
  573.             SetClip(clipRgn);
  574.             DisposeRgn(clipRgn);
  575.             SetPort(savedPort);
  576.         }
  577. }
  578.  
  579.  
  580.  
  581. void   GrowWindowGrow(WindowPeek   theWindow, Rect*   rectPtr)
  582. {
  583. /*    Draws the grow image for the window.  Diamond windows grow and shrink at
  584. twice the normal rate and only movement in the y-direction effects them when they
  585. are being resized.
  586.     To find the new length of each side, (*rectPtr).bottom is subtracted from
  587. dataRecord.midY, the y-coordinate of the middle of the window.
  588. */
  589. short        length, longLength;
  590.  
  591.     length = longLength = rectPtr->bottom - dataRecord.midY - 1;
  592.     longLength += 26;
  593.     MoveTo(dataRecord.midX - length, dataRecord.midY);
  594.     PenPat(&white);
  595.     Line(length, -length);
  596.     Line(length, length);
  597.     Line(-length, length);
  598.     Line(-length, -length);
  599.     PenPat(&gray);
  600.     Line(-26, 0);
  601.     Move(longLength, -length);
  602.     Line(0, -26);
  603.     Move(length, longLength);
  604.     Line(26, 0);
  605.     PenPat(&white);
  606.     Line(-longLength, longLength);
  607.     Line(-longLength, -longLength);
  608.     Line(longLength, -longLength);
  609.     Line(longLength, longLength);
  610. /* The Window Manager automatically resets the pen pattern to black when it stops
  611. calling this function.
  612. */
  613. }
  614.  
  615.  
  616.  
  617. void   SetUpStdZoom(void)
  618. {
  619. /* Sets up the stdState Rect so the window will be zoom ready.  This rectangle is
  620. always centered onscreen and does not take into account any maximum window size
  621. you may entend to enforce using GrowWindow().
  622. */
  623. GrafPtr        windMPort;
  624. Rect        theRect;
  625. short        xDistance, yDistance;
  626.  
  627.     GetPort(&windMPort);
  628.     theRect = windMPort->portRect;
  629.     InsetRect(&theRect, SCREEN_MARGIN, SCREEN_MARGIN + FRAME_WIDTH);
  630.     theRect.top += MBarHeight;
  631.     theRect.right -= SHADOW;
  632.     theRect.bottom -= 2;
  633. /* Make sure x and yDistance are even.                                                */
  634.     xDistance = (theRect.right - theRect.left) & MAKE_EVEN;
  635.     yDistance = (theRect.bottom - theRect.top) & MAKE_EVEN;
  636.     if (xDistance > yDistance)
  637.     {
  638.         OffsetRect(&theRect, (xDistance - yDistance) >> 1, 0);
  639.         theRect.right = theRect.left + yDistance;
  640.     }
  641.     else if (yDistance > xDistance)
  642.     {
  643.         OffsetRect(&theRect, 0, (yDistance - xDistance) >> 1);
  644.         theRect.bottom = theRect.top + xDistance;
  645.     }
  646.     dataRecord.stdRect = theRect;
  647. }
  648.  
  649.  
  650.  
  651. void   InitNewWindow(WindowPeek   theWindow)
  652. {
  653. /*   Sets up various window regions and allocates memory necessary for the
  654. operation of diamond shaped windows.
  655. */
  656. Rect            theRect;
  657. Str255            theTitle;
  658.  
  659.     theWindow->strucRgn = NewRgn();
  660.     theWindow->contRgn = NewRgn();
  661.     if (theWindow->goAwayFlag)
  662.     {
  663.         dataRecord.goAwayPoly = OpenPoly();
  664.             MoveTo(0, 0);
  665.             Line(8, -8);
  666.             Line(8, 8);
  667.             Line(-8, 8);
  668.             Line(-8, -8);
  669.         ClosePoly();
  670.         dataRecord.goAwayRgn = NewRgn();
  671.         OpenRgn();
  672.             FramePoly(dataRecord.goAwayPoly);
  673.         CloseRgn(dataRecord.goAwayRgn);
  674.     }
  675.     if (dataRecord.resizable)
  676.     {
  677.         dataRecord.growPoly = OpenPoly();
  678.             MoveTo(0, 0);
  679.             Line(8, -8);
  680.             Line(8, 8);
  681.             Line(-8, 8);
  682.             Line(-8, -8);
  683.             Line(5, -5);
  684.             Line(-2, -2);
  685.             Line(5, -5);
  686.             Line(5, 5);
  687.             Line(-1, 1);
  688.         ClosePoly();
  689.         dataRecord.growRgn = NewRgn();
  690.         OpenRgn();
  691.             MoveTo(0, 0);
  692.             Line(5, -5);
  693.             Line(-2, -2);
  694.             Line(5, -5);
  695.             Line(5, 5);
  696.             Line(-2, 2);
  697.             Line(5, 5);
  698.             Line(-8, 8);
  699.             Line(-8, -8);
  700.         CloseRgn(dataRecord.growRgn);
  701.     }
  702.     if (theWindow->spareFlag)
  703.     {
  704.         dataRecord.zoomPoly = OpenPoly();
  705.             MoveTo(5, -5);
  706.             Line(3, -3);
  707.             Line(8, 8);
  708.             Line(-8, 8);
  709.             Line(-8, -8);
  710.             Line(5, -5);
  711.             Line(5, 5);
  712.             Line(-5, 5);
  713.         ClosePoly();
  714.         dataRecord.zoomRgn = NewRgn();
  715.         OpenRgn();
  716.             FramePoly(dataRecord.goAwayPoly);
  717.         CloseRgn(dataRecord.zoomRgn);
  718.         SetUpStdZoom();
  719.         dataRecord.zoomedOut = FALSE;
  720.     }
  721. /* Initialize the global variable dataRecordHdl so data can be transferred from
  722. the global variable dataRecord into the window's private storage area.
  723. */
  724.     dataRecordHdl = (DataRecordHdl) NewHandle(sizeof(DataRecord));
  725.     theWindow->dataHandle = (Handle) dataRecordHdl;
  726.     theRect = theWindow->port.portRect;
  727.     if (theRect.bottom > theRect.right)
  728.     {
  729.     /* To ensure that each side of a window's portRect is even, the value is
  730.     ANDed with MAKE_EVEN, that is 0xFFFE.
  731.     */
  732.         theRect.right &= MAKE_EVEN;
  733.         theRect.bottom = theRect.right;
  734.     }
  735.     else
  736.     {
  737.         theRect.bottom &= MAKE_EVEN;
  738.         theRect.right = theRect.bottom;
  739.     }
  740.     theWindow->port.portRect = theRect;
  741. /*    Save title information that will allow diamond window title to be drawn more
  742. quiclky.
  743. */
  744.     BlockMove(*(theWindow->titleHandle), theTitle, 0xFF);
  745.     dataRecord.titleRgn = NULL;
  746.     NewTitle(theWindow, (Ptr) theTitle);
  747.     dataRecord.titleRgn = NewRgn();
  748. }
  749.  
  750.  
  751.  
  752. long   DoHit(WindowPeek   theWindow, Point   mouseClick)
  753. {
  754. /* Determines if a diamond window was hit by a mouseClick.  If so, returns the
  755. region in which the click occured.
  756. */
  757.     if (theWindow->visible)
  758.         if (theWindow->hilited)
  759.         {
  760.             if (theWindow->goAwayFlag)
  761.                 if (PtInRgn(mouseClick, dataRecord.goAwayRgn))
  762.                     return(wInGoAway);
  763.             if (dataRecord.resizable)
  764.                 if (PtInRgn(mouseClick, dataRecord.growRgn))
  765.                     return(wInGrow);
  766.             if (theWindow->spareFlag)    
  767.                 if (PtInRgn(mouseClick, dataRecord.zoomRgn))
  768.                     return(dataRecord.zoomedOut ? wInZoomIn : wInZoomOut);
  769.             if (PtInRgn(mouseClick, dataRecord.titleRgn))
  770.                 return(wInDrag);
  771.             if (PtInRgn(mouseClick, theWindow->contRgn))
  772.                 return(wInContent);
  773.         }
  774.         else
  775.         {
  776.             if (PtInRgn(mouseClick, dataRecord.titleRgn))
  777.                 return(wInDrag);
  778.             if (PtInRgn(mouseClick, theWindow->strucRgn))
  779.                 return(wInContent);
  780.         }
  781. }
  782.  
  783.  
  784.  
  785. void   WindowDisposal(WindowPeek   theWindow)
  786. {
  787. /* Releases memory occupied by auxiliary window data.
  788. */
  789.  
  790.     DisposeRgn(dataRecord.titleRgn);
  791.     if (theWindow->goAwayFlag)
  792.     {
  793.         KillPoly(dataRecord.goAwayPoly);
  794.         DisposeRgn(dataRecord.goAwayRgn);
  795.     }
  796.     if (dataRecord.resizable)
  797.     {
  798.         KillPoly(dataRecord.growPoly);
  799.         DisposeRgn(dataRecord.growRgn);
  800.     }
  801.     if (theWindow->spareFlag)
  802.     {
  803.         KillPoly(dataRecord.zoomPoly);
  804.         DisposeRgn(dataRecord.zoomRgn);
  805.     }
  806.     DisposHandle(theWindow->dataHandle);
  807. }
  808.  
  809.  
  810.  
  811. pascal long   main(varCode, theWindow, message, param)
  812. short            varCode;
  813. WindowPeek        theWindow;
  814. short            message;
  815. long            param;
  816. {
  817. /* Sets up registers, copies dataHandle information into global variables, dispatches
  818. control to other routines, and copies updated information back into the window's
  819. dataHandle.
  820. */
  821. long            returnVal = 0L;
  822.  
  823.     RememberA0();
  824.     SetUpA4();
  825.     if (message != wNew)
  826.     {
  827.         dataRecordHdl = (DataRecordHdl) theWindow->dataHandle;
  828.         BlockMove(*dataRecordHdl, &dataRecord, sizeof(DataRecord));
  829.     }
  830.     switch (message)
  831.     {
  832.         case wDraw:
  833.             DrawWindow(theWindow, param);
  834.             break;
  835.         case wHit:
  836.             returnVal = DoHit(theWindow, topLeft(param));
  837.             break;
  838.         case wJUST_DRAGGED:
  839.             theWindow->titleWidth = FALSE;
  840.         case wCalcRgns:
  841.             CalcRgns(theWindow);
  842.             break;
  843.         case wNew:
  844.             theWindow->spareFlag = varCode & ZOOM_MASK;
  845.             dataRecord.resizable = !(varCode & NO_GROW_MASK);
  846.             InitNewWindow(theWindow);
  847.             break;
  848.         case wDispose:
  849.             WindowDisposal(theWindow);
  850.             RestoreA4();
  851.             return(returnVal);
  852.             break;
  853.         case wDrawGIcon:
  854.             DrawGrowIcon(theWindow);
  855.             break;
  856.         case wGrow:
  857.             GrowWindowGrow(theWindow, (Rect *) param);
  858.             break;
  859.         case wNEW_TITLE:
  860.             NewTitle(theWindow, (Ptr) param);
  861.             break;
  862.     }
  863.     HLock(dataRecordHdl);
  864.     BlockMove(&dataRecord, *dataRecordHdl, sizeof(DataRecord));
  865.     HUnlock(dataRecordHdl);
  866.     RestoreA4();
  867.     return(returnVal);
  868. }